package  
{
	import flash.display.Sprite;
	import flash.net.SharedObject;
	import flash.net.SharedObjectFlushStatus;
	import flash.text.TextField;

	/**
	 * ...
	 * @author patsup
	 * 
	 * 		This is basically a structure that holds data for a single session (game), persistant across rounds.
	 * 	The displaying of it is mainly just for testing purposes. It is instantiated in the PGame class, 
	 * 	so other classes (such as PreRoundMenu) need accessor functions.
	 * 		EvaluatePayoutTiers() calculates/sets the payout tiers.
	 * 		GetPayoutTable() returns a string with the info the above had calculated.
	 * 		CalcWinningsWithBetAndScore() returns how much should be won, based on currentBet and score (using those tiers)
	 * 		ApplyRoundEnd() does the necessary actions for the end of a round.
	 * 		UpdateText() is mainly just for testing purposes (i.e. when displaying this class).
	 * 
	 * Set DEBUG_MODE to false in Main.as to not display (doesn't add to display list with addChild)
	 * 
	 * *** public functions
	 * 
	 * InitNewGame():void
	 * UpdateText():void
	 * ApplyRoundEnd():void
	 * 
	 * IncrBetSize():void
	 * DecrBetSize():void
	 * IncrNumTries():void
	 * 
	 * CalcWinningsWithBetAndScore():Number
	 * GetPayoutTable():String
	 * 
	 * GetCurrentBetSize():int
	 * GetTotalMoney():int
	 * GetNumRounds():int
	 * GetCurrentScore():int
	 * GetLastScore():int
	 * GetAvgScore():Number
	 * GetPerfectCount():int
	 * GetNumTries():int
	 * GetAvgNumTries():Number
	 * 
	 * *** protected functions
	 * InitImage():void
	 * 
	 * *** private functions
	 * EvaluatePayoutTiers():void
	 * 
	 */
	public class SessionStats extends Sprite
	{
		//session stats image parameters
		private const SS_COLOR:int = 0xC0C0C0;
		private const SS_ALPHA:Number = 0.3;
		private const SS_WIDTH:int = 160;
		private const SS_HEIGHT:int = 160;
		
		//default constants / constant parameters
		private const STARTING_DEFAULT_BET:int = 5;
		private const STARTING_MONEY:int = 100;
		private const MAX_BET_SIZE:int = 10;
		private const MIN_BET_SIZE:int = 3;
		private const BET_INCREMENT:int = 1;
		private const NUM_PAYOUT_TIERS:int = 4;
		private const TIER_RANGE_FRACTION_OF_TOTAL:int = 15;	//1/15th of the total sum of pirates possible (the score u get on forfeit)
		
		private var totalMoney:int;								//total amount of money
		private var numRounds:int;								//current round number playing
		private var currentScore:int;							//current score
		private var lastScore:int;								//score from last round
		private var avgScore:Number;							//avg score of pirates left in a round
		private var perfectCount:int;							//number of rounds won with score = 0
		private var currentBet:int;								//this round's wager
		private var numTries:int;								//number of dicerolls in a round
		private var avgNumTries:Number;							//avg tries a round lasts
		
		private var payoutTiers:Array = new Array();			//payout table tiers
		
		private var txtLabel:TextField;				//label
		private var gameRef:PGame;
		
		public function SessionStats(gameRef:PGame, xCoord:int, yCoord:int) 
		{
			this.gameRef = gameRef;
			x = xCoord;
			y = yCoord;
			txtLabel = new TextField();
			
			EvaluatePayoutTiers();		//payout tiers don't change now, so we can put this in the constructor
			InitNewGame();
		}
		
		//InitNewGame()
		public function InitNewGame():void
		{
			totalMoney = STARTING_MONEY;
			numRounds = 1;
			lastScore = -1;
			perfectCount = 0;
			currentBet = STARTING_DEFAULT_BET;
			numTries = 0;
			
			InitImage();
		}
		//Sets data upon loading a new game
		public function InitLoadGame(data:Object):void
		{
			currentBet = data.currentBet;
			totalMoney = data.totalMoney;
			numRounds = data.numRounds;
			currentScore = data.currentScore;
			lastScore = data.lastScore;
			avgScore = data.avgScore;
			perfectCount = data.perfectCount;
			numTries = data.numTries;
			avgNumTries = data.avgNumTries;
			
			InitImage();
		}
		
		//InitImage()
		//Initializes the image of the SessionStats
		protected function InitImage():void
		{
			graphics.beginFill(SS_COLOR, SS_ALPHA);
			graphics.drawRect(0, 0, SS_WIDTH, SS_HEIGHT);
			graphics.endFill();
			
			UpdateText();
			
			txtLabel.width = txtLabel.textWidth*1.5;
			txtLabel.height = txtLabel.textHeight * 1.5;
			txtLabel.x = 0;
			txtLabel.y = 0;
			//btnLabel.x = 0.5 * SS_WIDTH - 0.5 * btnLabel.width;
			//btnLabel.y = 0.5 * SS_HEIGHT - 0.5 * btnLabel.height;
			addChild(txtLabel);								//now add this txt label to the display list
			
		}
		
		//ApplyRoundEnd()
		//call at the end of a round to calculate stats, determine winnings, and see if you "lost" (not enough money to bet next round)
		//"LOSING" currently does nothing, but there's a check for it!
		public function ApplyRoundEnd():void
		{
			var _score:int = gameRef.GetRoundScore();
			if (numRounds == 1) {
				avgScore = _score;
				avgNumTries = numTries;
			} else {
				avgScore = ((avgScore * (numRounds-1)) + _score) / (numRounds);
				avgNumTries = ((avgNumTries * (numRounds-1)) + numTries) / (numRounds);
			}
			if (_score == 0) {								//perfect score!
				perfectCount++;
			}
			lastScore = _score;
			numRounds++;
			numTries = 0;
			
			totalMoney += CalcWinningsWithBetAndScore();	//adjust total money by win/lose amount
			
			if (currentBet > totalMoney) {					//if bet > money left reduce betsize
				currentBet = totalMoney;
			}
			if (currentBet < MIN_BET_SIZE) {
				trace("wow i didn't think you could lose this game but you did");		//you lose
			}
		}
		
		//GetPayoutTable()
		//returns payout table as a string so it could be displayed
		public function GetPayoutTable():String
		{
			var _pt:String;
			var _payout:int = payoutTiers[0].GetPayout();
			
			_pt = "Payout Table\nScore: " + payoutTiers[0].GetTier() + " = " + _payout + "x bet";
			for (var i:int = 1; i < payoutTiers.length; i++)
			{
				_payout = payoutTiers[i].GetPayout();
				_pt += "\nScore: " + (payoutTiers[i - 1].GetTier() + 1) + "-" + payoutTiers[i].GetTier() + " = ";
				if(_payout != 0)
					_pt += _payout + " x bet";
				else
					_pt += "breakeven";
			}
			_pt += "\nScores above " + (payoutTiers[payoutTiers.length - 1].GetTier() + 1) + " = loss";
			return _pt;
		}
		//CalcWinningsWithBetAndScore()
		//returns the amount of money won/lost, based on your current bet and score
		public function CalcWinningsWithBetAndScore():Number
		{
			var _winnings:Number = currentBet;
			var _score:int = gameRef.GetRoundScore();
			//if (_score == 0) {
				//_winnings *= 5;
			//} else if (_score < 4) {
				//_winnings *= 3;
			//} else if (_score < 7) {
				//_winnings *= 2;
			//} else if (_score < 10) {
				//_winnings *= 1;
			//} else if (_score < 13) {
				//no change in money, i.e. you make back what you bet
				//_winnings *= 0;
			//} else {
				//_winnings *= -1;
			//}
			var i:int = 0;
			var _tierNotFound:Boolean = true;
			while (_tierNotFound && i < payoutTiers.length) {
				if (_score <= payoutTiers[i].GetTier()) {
					_winnings *= payoutTiers[i].GetPayout();
					_tierNotFound = false;
				}
				i++;
			}
			if (_tierNotFound) {
				_winnings *= -1;
			}
			return _winnings;
		}
		
		//EvaluatePayoutTiers()
		//calculate/sets the payout tiers and stores them in a payoutTiers:Array
		//based on the total number of pirates, NUM_PAYOUT_TIERS, and TIER_RANGE_FRACTION_OF_TOTAL
		private function EvaluatePayoutTiers():void
		{
			var _pirateTotalSum:int  = 0;
			var i:int;
			for (i = 1; i <= gameRef.TotalNumPirates(); i++) {
				_pirateTotalSum += i;
			}
			//default of 9 pirates means: sum=45, fraction=1/15th, so Range = 45/15 = 3
			var _tierRange:Number = _pirateTotalSum / TIER_RANGE_FRACTION_OF_TOTAL;
			
			
			for (i = 0; i <= NUM_PAYOUT_TIERS; i++) {
				payoutTiers[i] = new Payout(i * _tierRange, NUM_PAYOUT_TIERS - i);
				//tier range from i to i+1, i+1 to i+2, etc... payout multiplier
				//trace("tier<=" + payoutTiers[i].GetTier() + " payout:" + payoutTiers[i].GetPayout());		
			}
			
		}
		
		//UpdateText()
		//This function is mainly just used for testing purposes since anything from
		//this function shouldn't actually be displayed.
		public function UpdateText():void
		{
			txtLabel.text = "Round #" + numRounds;
			txtLabel.appendText("\nMoney: " + totalMoney);
			txtLabel.appendText("\nBet: $" + currentBet);
			txtLabel.appendText("\n\nScore: " + gameRef.GetRoundScore());
			txtLabel.appendText(",  Last: ");
			if (lastScore >= 0) {
				txtLabel.appendText(lastScore.toString());
			}
			txtLabel.appendText(",  Avg: ");
			if (avgScore) {
				txtLabel.appendText(avgScore.toFixed(1).toString());
			}
			txtLabel.appendText("\n#Tries: " + numTries);
			txtLabel.appendText(",  Avg: " );
			if (avgNumTries) {
				txtLabel.appendText(avgNumTries.toFixed(1).toString());
			}
			if (perfectCount > 0) {
				txtLabel.appendText("\n\n" + perfectCount + " perfect scores!");
			}
		}
		
		//IncrBetSize()
		//adjusts the current bet for this round
		public function IncrBetSize():void
		{
			if ((currentBet + BET_INCREMENT <= totalMoney) &&						//make sure we have enough to bet
					(currentBet + BET_INCREMENT <= MAX_BET_SIZE)) {
				currentBet += BET_INCREMENT;
			}
			//if (currentBet + BET_INCREMENT <= totalMoney) {			//no max bet size!
				//currentBet += BET_INCREMENT;
			//}
		}
		
		//DecrBetSize()
		//adjusts the current bet for this round
		public function DecrBetSize():void
		{
			if (currentBet - BET_INCREMENT >= MIN_BET_SIZE) {
				currentBet -= BET_INCREMENT;
			}
		}
		
		//IncrNumTries()
		public function IncrNumTries():void {numTries++;}
		
		
		//accessor functions
		
		//GetCurrentBetSize()
		//accessor function to return how much is being bet this round
		public function GetCurrentBetSize():int { return currentBet;}
		public function GetTotalMoney():int {return totalMoney;}
		public function GetNumRounds():int {return numRounds;}
		public function GetCurrentScore():int {return currentScore;}
		public function GetLastScore():int {return lastScore;}
		public function GetAvgScore():Number {return avgScore;}
		public function GetPerfectCount():int {return perfectCount;}
		public function GetNumTries():int {return numTries;}
		public function GetAvgNumTries():Number {return avgNumTries;}
		
		public function SaveGameData(savedData:SharedObject):void
		{
			savedData.data.hasData = true;
			savedData.data.currentBet = currentBet;
			savedData.data.totalMoney = totalMoney;
			savedData.data.numRounds = numRounds;
			savedData.data.currentScore = currentScore;
			savedData.data.lastScore = lastScore;
			savedData.data.avgScore = avgScore;
			savedData.data.perfectCount = perfectCount;
			savedData.data.numTries = numTries;
			savedData.data.avgNumTries = avgNumTries;
			
			var _ts:Date = new Date();
			var _timeStamp:String = _ts.month + "/" + _ts.date + "/" + _ts.fullYear + " " + _ts.toLocaleTimeString();
			trace("timeStamp: " + _timeStamp);
			savedData.data.timeStamp = _timeStamp;

			if (savedData.flush() == SharedObjectFlushStatus.FLUSHED)
			{
				trace("saved data flush success");
			} else {
				trace("saved data flush failed");
			}
		}
	}

}

class Payout
{
	private var tier:int;
	private var payout:Number;
	public function Payout(t:int, p:Number) {
		tier = t;
		payout = p;
	}
	public function GetTier():int {return tier;}			//$-value for the payout tier
	public function GetPayout():Number {return payout;}		//payout multiplier
	
}
